package com.yami.shop.api.controller;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.bean.app.dto.ApiOrderRefundDto;
import com.yami.shop.bean.app.param.OrderRefundExpressParam;
import com.yami.shop.bean.app.param.OrderRefundParam;
import com.yami.shop.bean.dto.OrderRefundDto;
import com.yami.shop.bean.enums.OrderStatus;
import com.yami.shop.bean.enums.RefundStatusEnum;
import com.yami.shop.bean.enums.RefundType;
import com.yami.shop.bean.enums.ReturnMoneyStsType;
import com.yami.shop.bean.model.Order;
import com.yami.shop.bean.model.OrderItem;
import com.yami.shop.bean.model.OrderRefund;
import com.yami.shop.bean.model.RefundDelivery;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.service.OrderItemService;
import com.yami.shop.service.OrderRefundService;
import com.yami.shop.service.OrderService;
import com.yami.shop.service.RefundDeliveryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@RestController
@RequestMapping("/p/orderRefund")
@Api(tags = "订单退款接口")
@AllArgsConstructor
public class OrderRefundController {

    private final OrderRefundService orderRefundService;

    private final OrderService orderService;

    private final MapperFacade mapperFacade;

    private final Snowflake snowflake;

    private final OrderItemService orderItemService;

    private final RefundDeliveryService refundDeliveryService;

    @PostMapping("/apply")
    @ApiOperation(value = "申请退款", notes = "申请退款")
    public ResponseEntity<String> apply(@Valid @RequestBody OrderRefundParam orderRefundParam) {
        String userId = SecurityUtils.getUser().getUserId();
        // 获取订单信息
        Order order = orderService.getOrderByOrderNumberAndUserId(orderRefundParam.getOrderNumber(), userId, true);

        if (!Objects.equals(order.getIsPayed(), 1)) {
            // 当前订单还未付款，无法申请
            throw new YamiShopBindException("yami.order.not.paid");
        }

        if (Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
            // 当前订单已失败，不允许退款
            throw new YamiShopBindException("yami.order.has.failed");
        }

        if (Objects.equals(order.getStatus(), OrderStatus.WAIT_GROUP.value())) {
            // 当前订单正在等待成团状态，需等待成团才能进行下一步操作
            throw new YamiShopBindException("yami.group.user.join.check");
        }


//        if (!Objects.equals(orderRefundParam.getRefundType(),RefundType.ALL.value()) && Objects.equals(order.getStatus(),OrderStatus.PADYED.value())) {
//            throw new YamiShopBindException("未发货订单仅支持整单退款");
//        }
//        // 代发货整单退款不可以输入金额，为固定全额退款
//        if (Objects.equals(orderRefundParam.getRefundType(),RefundType.ALL.value()) && Objects.equals(order.getStatus(),OrderStatus.PADYED.value())) {
//            orderRefundParam.setRefundAmount(order.getActualTotal());
//        }

        if (orderRefundParam.getRefundAmount() > order.getActualTotal()) {
            // 退款金额已超出订单金额，无法申请
            throw new YamiShopBindException("yami.refund.exceeded.amount");
        }
        boolean isOrderStatus = Objects.equals(order.getStatus(), OrderStatus.CONSIGNMENT.value()) || Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value());
        //待收货或者确认收货 -> 整单退款 -> 退款金额 < 订单金额 - 运费金额
        if (isOrderStatus && orderRefundParam.getRefundType().equals(RefundType.ALL.value())) {
            Double refundAmount = Arith.sub(order.getActualTotal(),order.getFreightAmount());
            if (orderRefundParam.getRefundAmount() > refundAmount){
                // 退款金额已超出订单金额，无法申请
                throw new YamiShopBindException("yami.refund.exceeded.amount");
            }
        }

        if (!orderRefundService.checkRefundDate(order)) {
            // 该商品已经确认收货超过x天
            String dayMsg = I18nMessage.getMessage("yami.order.refund.day.check");
            String dayMsg2 = I18nMessage.getMessage("yami.order.refund.day.check2");
            throw new YamiShopBindException(dayMsg + Constant.MAX_FINALLY_REFUND_TIME + dayMsg2);
        }
        if (Objects.equals(order.getOrderType(),Constant.ORDER_TYPE_SCORE)) {
            // 积分商品，无法退款
            throw new YamiShopBindException("yami.order.refund.score");
        }
        if (Objects.equals(orderRefundParam.getRefundType(),RefundType.ALL.value()) && (!Objects.isNull(order.getRefundStatus()) && !Objects.equals(order.getRefundStatus(), RefundStatusEnum.DISAGREE.value()))) {
            // 该订单已有商品正在退款中，不能再进行整单退款
            throw new YamiShopBindException("yami.order.refund.go.on");
        }
        // 生成退款单信息
        OrderRefund newOrderRefund = new OrderRefund();

        // 获取所有正在进行中的退款订单
        List<OrderRefund> orderRefunds = orderRefundService.getProcessingOrderRefundByOrderId(order.getOrderId());

        for (OrderRefund orderRefund : orderRefunds) {
            if (Objects.equals(RefundType.ALL.value(),orderRefund.getRefundType())) {
                // 该订单正在进行整单退款，无法进行新的退款操作
                throw new YamiShopBindException("yami.order.all.refund.check");
            }
            if (Objects.equals(orderRefund.getOrderItemId(), orderRefundParam.getOrderItemId())) {
                // 该商品正在进行退款中，无法进行新的退款操作
                throw new YamiShopBindException("yami.order.refund.go.on");
            }
        }

        // 如果存在分销订单，则计算分销总金额
        List<OrderItem> orderItemList = orderItemService.getOrderItemsByOrderNumber(order.getOrderNumber(), I18nMessage.getDbLang());
        // 获取所有的订单项总数
        int orderItemCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
        // 判断退款单类型（1:整单退款,2:单个物品退款）
        if (orderRefundParam.getRefundType().equals(RefundType.ALL.value())) {
            // 全部物品退款
            // 计算该订单项的分销金额
            newOrderRefund.setDistributionTotalAmount(orderService.sumTotalDistributionAmountByOrderItem(orderItemList));
            // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
            newOrderRefund.setPlatformRefundAmount(order.getPlatformAmount());
        } else {
            // 部分物品退款
            OrderItem orderItem = orderItemService.getOne(new LambdaQueryWrapper<OrderItem>()
                    .eq(OrderItem::getOrderItemId, orderRefundParam.getOrderItemId())
                    .eq(OrderItem::getOrderNumber, orderRefundParam.getOrderNumber()));
            if (orderItem == null) {
                // 该物品在订单中不存在
                throw new YamiShopBindException("yami.item.not.exist");
            }

            boolean isCanRefund = false;
            //  查看是否有支付金额和积分都为空的订单，有则抛出异常
            for (OrderItem item : orderItemList) {
                if(item.getActualTotal() <= 0.0 && item.getUseScore() <= 0.0){
                    isCanRefund = true;
                    break;
                }
            }
            if (isCanRefund) {
                // 该订单部分订单项支付金额和积分为0，无法使用部分退款
                throw new YamiShopBindException("yami.refund.amount.check");
            }

            // 是否为最后一项
            boolean isEndItem = Objects.equals(orderRefunds.size(), orderItemCount - 1);
            // 如果为最后一项并且不为确认收货或待收货状态，则进行加上运费判断是不是为部分退款
            double itemActualTotal = orderItem.getActualTotal();
            if(isEndItem && !isOrderStatus) {
                itemActualTotal = Arith.add(orderItem.getActualTotal(), order.getFreightAmount());
            }
            if (order.getPlatformAmount() > 0 && !Arith.isEquals(orderRefundParam.getRefundAmount(), itemActualTotal)) {
                // 该订单有使用平台优惠，无法使用部分退款
                throw new YamiShopBindException("yami.refund.platform.amount.check");
            }
            // 计算该订单项的分销金额
            newOrderRefund.setDistributionTotalAmount(orderService.sumTotalDistributionAmountByOrderItem(Collections.singletonList(orderItem)));

            // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
            //此处设置实际平台抵现金额
            newOrderRefund.setPlatformRefundAmount(orderItem.getPlatformShareReduce());

            // 退款物品数量为null或者0时，则为退款全部数量
            if (orderRefundParam.getGoodsNum() <= 0) {
                orderRefundParam.setGoodsNum(orderItem.getProdCount());
            }

            // 判断退款数量是否溢出
            if (orderRefundParam.getGoodsNum() > orderItem.getProdCount()) {
                // 退款物品数量已超出订单中的数量，不允许申请
                throw new YamiShopBindException("yami.refund.num.check");
            }

            // 判断退款金额是否超出订单金额两种情况
            double refundSingleAmount = Arith.div(orderRefundParam.getRefundAmount(), orderRefundParam.getGoodsNum(), 3);
            double singleAmount = Arith.div(orderItem.getActualTotal(), orderItem.getProdCount(), 3);
            double productTotalAmount = orderItem.getProductTotalAmount();
            // 1.如果是此笔订单最后一件并且不为确认收货或待收货状态，则订单项加上运费进行判断。
            if(isEndItem && !isOrderStatus){
                productTotalAmount = Arith.add(orderItem.getProductTotalAmount(), order.getFreightAmount());
                singleAmount = Arith.add(singleAmount, order.getFreightAmount());
            }
            // 2.如果不是直接跟订单项进行判断
            if (refundSingleAmount > productTotalAmount || refundSingleAmount > singleAmount) {
                // 退款金额已超出订单金额，无法申请
                throw new YamiShopBindException("yami.refund.exceeded.amount");
            }

            // 一个订单项只能申请一次退款
            for (OrderRefund orderRefund : orderRefunds) {
                if (Objects.equals(orderRefund.getOrderId(), orderItem.getOrderItemId())) {
                    // 退款订单项已处理，请勿重复申请
                    throw new YamiShopBindException("yami.order.processed");
                }
            }

        }

        newOrderRefund.setShopId(order.getShopId());
        newOrderRefund.setUserId(order.getUserId());
        newOrderRefund.setOrderId(order.getOrderId());
        newOrderRefund.setRefundSn(String.valueOf(snowflake.nextId()));
        newOrderRefund.setRefundType(orderRefundParam.getRefundType());

        newOrderRefund.setRefundAmount(orderRefundParam.getRefundAmount());
        if (Objects.equals(RefundType.ALL.value(),orderRefundParam.getRefundType())) {
            newOrderRefund.setOrderItemId(0L);
        } else {
            newOrderRefund.setOrderItemId(orderRefundParam.getOrderItemId());
//            // 待发货状态-最后一件商品进行退款，退款金额 =  商品金额 + 订单运费金额
//            if (Objects.equals(order.getStatus(),OrderStatus.PADYED.value()) && order.getFreightAmount() > 0){
//                if (Objects.equals(orderRefunds.size(),orderItemCount - 1)){
//                    newOrderRefund.setRefundAmount(Arith.add(newOrderRefund.getRefundAmount(),order.getFreightAmount()));
//                }
//            }
        }
        newOrderRefund.setGoodsNum(orderRefundParam.getGoodsNum());
        newOrderRefund.setApplyType(orderRefundParam.getApplyType());
        if (Objects.equals(orderRefundParam.getApplyType(),2)){
            newOrderRefund.setIsReceiver(true);
        }else {
            newOrderRefund.setIsReceiver(orderRefundParam.getIsReceiver());
        }
        newOrderRefund.setBuyerReason(orderRefundParam.getBuyerReason());
        newOrderRefund.setBuyerDesc(orderRefundParam.getBuyerDesc());
        newOrderRefund.setBuyerMobile(orderRefundParam.getBuyerMobile());
        newOrderRefund.setPhotoFiles(orderRefundParam.getPhotoFiles());
        newOrderRefund.setReturnMoneySts(ReturnMoneyStsType.APPLY.value());
        newOrderRefund.setApplyTime(new Date());
        newOrderRefund.setUpdateTime(new Date());
        orderRefundService.applyRefund(newOrderRefund);

        return ResponseEntity.ok(newOrderRefund.getRefundSn());
    }

    /**
     * 用户提交物流公司信息
     */
    @PostMapping("/submitExpress")
    @ApiOperation(value = "提交退款订单物流填写信息", notes = "")
    public ResponseEntity<String> submitExpress(@Valid @RequestBody OrderRefundExpressParam orderRefundExpressParam) {
        OrderRefund orderRefund = orderRefundService.getOrderRefundByRefundSn(orderRefundExpressParam.getRefundSn());
        if (Objects.isNull(orderRefund)) {
            // 查询不到退款信息
            throw new YamiShopBindException("yami.cannot.find");
        }

        String userId = SecurityUtils.getUser().getUserId();
        if (!Objects.equals(orderRefund.getUserId(), userId)) {
            // 申请失败，您没有该权限
            throw new YamiShopBindException("yami.not.permission");
        }

        if (!Objects.equals(orderRefund.getApplyType(), 2)) {
            // 当前申请类型不允许提交物流信息操作
            throw new YamiShopBindException("yami.not.submission");
        }

        if (!Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.PROCESSING.value())) {
            // 当前状态不允许提交物流信息操作
            throw new YamiShopBindException("yami.not.submission.delivery");
        }

        // 填写物流信息
        RefundDelivery refundDelivery = refundDeliveryService.getOne(new LambdaQueryWrapper<RefundDelivery>()
                .eq(RefundDelivery::getRefundSn, orderRefundExpressParam.getRefundSn()));
        refundDelivery.setSenderMobile(orderRefundExpressParam.getMobile());
        refundDelivery.setSenderRemarks(orderRefundExpressParam.getSenderRemarks());
        refundDelivery.setDeyId(orderRefundExpressParam.getExpressId());
        refundDelivery.setDeyName(orderRefundExpressParam.getExpressName());
        refundDelivery.setDeyNu(orderRefundExpressParam.getExpressNo());
        refundDelivery.setImgs(orderRefundExpressParam.getImgs());
        refundDelivery.setCreateTime(new Date());

        // 更新退款单信息
        orderRefund.setReturnMoneySts(ReturnMoneyStsType.CONSIGNMENT.value());
        orderRefund.setShipTime(new Date());
        orderRefund.setUpdateTime(new Date());

        orderRefundService.submitExpress(orderRefund, refundDelivery);
        // 提交成功
        return ResponseEntity.ok(I18nMessage.getMessage("yami.submitted.successfully"));
    }

    /**
     * 用户修改物流公司信息
     */
    @PutMapping("/reSubmitExpress")
    @ApiOperation(value = "修改退款订单物流填写信息", notes = "修改物流公司信息")
    public ResponseEntity<String> updateExpress(@Valid @RequestBody OrderRefundExpressParam orderRefundExpressParam) {
        String userId = SecurityUtils.getUser().getUserId();
        OrderRefund orderRefund = orderRefundService.getOrderRefundByRefundSn(orderRefundExpressParam.getRefundSn());
        if (Objects.isNull(orderRefund)) {
            // 查询不到退款信息
            throw new YamiShopBindException("yami.cannot.find");
        }

        if (!Objects.equals(orderRefund.getUserId(), userId)) {
            // 申请失败，您没有此权限
            throw new YamiShopBindException("yami.not.permission");
        }

        if (!Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.CONSIGNMENT.value())) {
            // 当前状态不允许更新物流信息操作
            throw new YamiShopBindException("yami.not.update.delivery");
        }

        // 填写物流信息
        RefundDelivery refundDelivery = refundDeliveryService.getOne(new LambdaQueryWrapper<RefundDelivery>()
                .eq(RefundDelivery::getRefundSn, orderRefundExpressParam.getRefundSn()));
        refundDelivery.setSenderMobile(orderRefundExpressParam.getMobile());
        refundDelivery.setDeyId(orderRefundExpressParam.getExpressId());
        refundDelivery.setSenderRemarks(orderRefundExpressParam.getSenderRemarks());
        refundDelivery.setDeyNu(orderRefundExpressParam.getExpressNo());
        refundDelivery.setImgs(orderRefundExpressParam.getImgs());
        refundDelivery.setReceiverMobile(orderRefundExpressParam.getMobile());
        refundDelivery.setDeyName(orderRefundExpressParam.getExpressName());

        // 更新退款单信息
        orderRefund.setUpdateTime(new Date());

        orderRefundService.submitExpress(orderRefund, refundDelivery);
        // 修改成功
        return ResponseEntity.ok(I18nMessage.getMessage("yami.activity.update.success"));
    }

    /**
     * 用户撤销退货退款申请
     */
    @PutMapping("/cancel")
    @ApiOperation(value = "撤销退货退款申请", notes = "")
    public ResponseEntity<String> cancel(@RequestBody String refundSn) {
        OrderRefundDto orderRefund = orderRefundService.getOrderRefundByRefundSn(refundSn);
        if (Objects.isNull(orderRefund)) {
            // 撤销失败 退款订单不存在
            throw new YamiShopBindException("yami.revocation.failed");
        }
        if (Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.PROCESSING.value())) {
            // 卖家正在处理退款，不能撤销退款申请
            throw new YamiShopBindException("yami.shop.processing.check");
        }
        if (Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.CONSIGNMENT.value())) {
            // 买家已发货，不能撤销退款申请
            throw new YamiShopBindException("yami.user.delivery.check");
        }
        if (Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.RECEIVE.value())) {
            // 卖家已收货，不能撤销退款申请
            throw new YamiShopBindException("yami.user.receipt.check");
        }
        if (Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.SUCCESS.value())) {
            throw new YamiShopBindException("yami.refund.success.check");
        }
        String userId = SecurityUtils.getUser().getUserId();

        // 查看订单是否还有处于处理中的退款单，如果没有则修改订单退款状态为关闭状态
        Order order = orderService.getOrderByOrderNumberAndUserId(orderRefund.getOrderNumber(),userId,true);

        //如果订单状态为待发货、包含运费、单个商品退款，且所有订单项都进行退款，则不能再取消退款（取消退款后再退款会导致重复退运费bug）
        if (Objects.equals(order.getStatus(),OrderStatus.PADYED.value()) && Objects.equals(orderRefund.getRefundType(),2) && order.getFreightAmount()>0){
            // 退款数量
            int refundCount = orderRefundService.count(new LambdaQueryWrapper<OrderRefund>()
                    .gt(OrderRefund::getReturnMoneySts, 1)
                    .lt(OrderRefund::getReturnMoneySts, 6)
                    .eq(OrderRefund::getOrderId, order.getOrderId())
            );
            // 订单项数量
            int orderItemCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
            if (refundCount == orderItemCount){
                // 该订单所有商品都进行退款，已无法取消退款
                throw new YamiShopBindException("yami.refund.finish.check");
            }
        }

        if (Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.SUCCESS.value()) ||
                Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.FAIL.value()) ||
                Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.REJECT.value()) ||
                Objects.equals(orderRefund.getReturnMoneySts(), ReturnMoneyStsType.CANCEL.value())) {
            // 撤销失败 当前状态不允许此操作
            throw new YamiShopBindException("yami.refund.status.check");
        }

        Date now = new Date();
        orderRefund.setReturnMoneySts(ReturnMoneyStsType.FAIL.value());
        orderRefund.setCancelTime(now);
        orderRefund.setUpdateTime(now);
        orderRefundService.updateById(orderRefund);


        List<OrderRefund> orderRefundList = orderRefundService.list(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, order.getOrderId()));
        long count = orderRefundList.stream().filter(item -> Objects.equals(item.getReturnMoneySts(), ReturnMoneyStsType.APPLY.value())
                || Objects.equals(item.getReturnMoneySts(), ReturnMoneyStsType.PROCESSING.value())
                || Objects.equals(item.getReturnMoneySts(), ReturnMoneyStsType.CONSIGNMENT.value())
                || Objects.equals(item.getReturnMoneySts(), ReturnMoneyStsType.RECEIVE.value())).count();
        if (count == 0) {
            order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
            orderService.updateById(order);
        }
        // 撤销成功
        return ResponseEntity.ok(I18nMessage.getMessage("yami.undo.successfully"));
    }


    /**
     * 查看退款订单详情
     */
    @GetMapping("/info")
    @ApiOperation(value = "查看退款订单详情", notes = "查看退款订单详情")
    public ResponseEntity<ApiOrderRefundDto> info(String refundSn) {
        // 查询详情
        OrderRefundDto orderRefundDto = orderRefundService.getOrderRefundByRefundSn(refundSn);

        if (orderRefundDto == null) {
            // 查看失败 该退款订单不存在
            throw new YamiShopBindException("yami.failed.not.exist");
        }

        if (!Objects.equals(orderRefundDto.getUserId(), SecurityUtils.getUser().getUserId())) {
            // 查看失败 您没有此权限
            throw new YamiShopBindException("yami.failed.not.permiso");
        }

        ApiOrderRefundDto apiOrderRefundDto = mapperFacade.map(orderRefundDto, ApiOrderRefundDto.class);
        return ResponseEntity.ok(apiOrderRefundDto);
    }

    /**
     * 查看我的退款订单列表
     */
    @GetMapping("/list")
    @ApiOperation(value = "我的退款订单列表", notes = "我的退款订单列表，显示数量时候")
    @ApiImplicitParam(name = "applyType",value = "申请类型: 0/null 全部  1仅退款  2退款退货",required = false,dataType = "Integer")
    public ResponseEntity<IPage<ApiOrderRefundDto>> list(PageParam<OrderRefundDto> page,
                                                         @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) Integer applyType) {
        OrderRefundDto orderRefundDto = new OrderRefundDto();
        orderRefundDto.setUserId(SecurityUtils.getUser().getUserId());
        // 0/null全部  1仅退款 2退款退货
        if (Objects.equals(0,applyType)){
            applyType = null;
        }
        orderRefundDto.setApplyType(applyType);
        IPage<OrderRefundDto> pageList = orderRefundService.getPage(page, orderRefundDto, startTime, endTime);

        // 克隆对象
        @SuppressWarnings("unchecked") IPage<ApiOrderRefundDto> apiPageList = mapperFacade.map(pageList, IPage.class);
        apiPageList.setRecords(mapperFacade.mapAsList(pageList.getRecords(), ApiOrderRefundDto.class));
        return ResponseEntity.ok(apiPageList);
    }

}
